# Workflow Configuration

To create a workflow, simply create a new `Workflow` object. For example, a simple 2-step workflow would look like:

```ts
import Hatchet, { Workflow } from "@hatchet-dev/typescript-sdk";

const hatchet = Hatchet.init();

const workflow: Workflow = {
  id: "example",
  description: "test",
  on: {
    event: "user:create",
  },
  steps: [
    {
      name: "step1",
      run: (ctx) => {
        console.log("executed step1!");
        return { step1: "step1" };
      },
    },
    {
      name: "step2",
      parents: ["step1"],
      run: (ctx) => {
        console.log("executed step2!");
        return { step2: "step2" };
      },
    },
  ],
};
```

You'll notice that the workflow defines a workflow trigger (in this case, on the event `user:create`), and the workflow definition. The workflow definition includes a series of steps which is simply an array of `Step` objects.

Each step has a `run` prop which is a function that with a `context` augment. The `context` argument is a `Context` object, which contains information about the workflow, such as the input data and the output data of previous steps.

To create multi-step workflows, you can use `parents` to define the steps which the current step depends on. In the example, `step2` will not invoke until after `step1` completes.

## Retrieving Workflow Input Data

You can get access to the workflow's input data, such as the event data or other specified input data, by using the `ctx.workflowInput()` method on the `context` argument, which is the first argument to the step function. It's also recommended that you typecast this to the `Context<T>` type, where `T` is the type of the input data. For example:

```ts
type MyType = {
  name: string;
};

const stepPrintsInput: Step = {
  name: "step2",
  parents: ["step1"],
  run: (ctx: Context<MyType>) => {
    console.log("executed step2!", ctx.workflowInput().name);
  },
};
```

## Step Outputs

Step outputs should be a of type `Record<string, any>`, should be `JSON` serializable, and are optional. For example:

```ts
const stepReturnsData: Step = {
  name: "step2",
  run: (ctx) => {
    return { awesome: "data" };
  },
};
```

Future steps can access this output through the context (`ctx`) parameter `ctx.stepOutput("<step_name>")`. In this example, a future step could access this data via `context.stepOutput("step2")`:

```ts
const futureStep: Step = {
  name: "step3",
  run: (ctx) => {
    const uppercaseStep2 = ctx.stepOutput("step2")["awesome"].toUpperCase();
    return { uppercase: uppercaseStep2 };
  },
};
```

Remember, a step that depends on previous step data should include this dependency in the `parents` array.

## Timeouts

**The default timeout on Hatchet is 60 seconds per step run**.

You can declare a timeout for a step by passing `timeout` to the `Step` definition. Timeouts are strings in the format of `1h`, `1m`, `1s`, etc. For example, to timeout a step after 5 minutes, you can do the following:

```ts
const stepWithTimeout: Step = {
  name: "step2",
  run: (ctx) => {
    console.log("executed step2!");
    return { step2: "step2" };
  },
  timeout: "5m",
};
```

## Cancellations

When a step is running and needs to be cancelled, Hatchet will send a cancellation signal to the step via it's context. This cancellation signal can be retrieved via `ctx.controller.signal` which returns an [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController), and is used by many HTTP libraries to cancel active requests. You can also case on the `signal.aborted` property to check if the step has been cancelled. For example:

```ts
{
    "step1",
    run: async (ctx) => {
      const { data } = ctx.workflowInput();
      const { signal } = ctx.controller;

      if (signal.aborted) throw new Error("step1 was aborted");

      console.log("starting step1 and waiting 5 seconds...", data);
      await sleep(5000);

      if (signal.aborted) throw new Error("step1 was aborted");

      // NOTE: the AbortController signal can be passed to many http libraries to cancel active requests
      // fetch(url, { signal })
      // axios.get(url, { signal })

      console.log("executed step1!");
      return { step1: `step1 results for ${data}!` };
    },
  },
```
